home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Archives / GNU / GNUPLOTsrc.lha / datafile.c < prev    next >
C/C++ Source or Header  |  1996-01-22  |  34KB  |  1,327 lines

  1. #ifndef lint
  2. static char    *RCSid = "$Id: datafile.c,v 1.17 1995/12/12 22:10:46 drd Exp $";
  3. #endif
  4.  
  5.  
  6. /*
  7.  * this file provides the functions to handle data-file reading..
  8.  * takes care of all the pipe / stdin / index / using worries
  9.  */
  10.  
  11. /*{{{  notes*/
  12. /* couldn't decide how to implement 'thru' only for 2d and 'index'
  13.  * for only 3d, so I did them for both - I can see a use for
  14.  * index in 2d, especially for fit.
  15.  *
  16.  * I keep thru for backwards compatibility, and extend it to allow
  17.  * more natural plot 'data' thru f(y) - I (personally) prefer
  18.  * my syntax, but then I'm biased...
  19.  *
  20.  * - because I needed it, I have added a range of indexes...
  21.  * (s)plot 'data' [index i[:j]]
  22.  *
  23.  * also every a:b:c:d:e:f  - plot every a'th point from c to e,
  24.  * in every b lines from d to f
  25.  * ie for (line=d; line<=f; line+=b)
  26.  *     for (point=c; point >=e; point+=a)
  27.  *
  28.  *
  29.  * I dont like mixing this with the time series hack... I am
  30.  * very into modular code, so I would prefer to not have to
  31.  * have _anything_ to do with time series... for example,
  32.  * we just look at columns in file, and that is independent
  33.  * of 2d/3d. I really dont want to have to pass a flag to
  34.  * this is plot or splot. 
  35.  *
  36.  * use a global array df_timecol[] - cleared by df_open, then
  37.  * columns needing time set by client.
  38.  *
  39.  * Now that df_2dbinary() and df_3dbinary() are here, I am seriously
  40.  * tempted to move get_data() and get_3ddata() in here too
  41.  *
  42.  * public variables declared in this file.
  43.  *    int df_no_use_specs - number of columns specified with 'using'
  44.  *    int df_line_number  - for error reporting
  45.  *    int df_datum        - increases with each data point
  46.  *    TBOOLEAN df_binary  - it's a binary file
  47.  *        [ might change this to return value from df_open() ]
  48.  *    int df_eof          - end of file
  49.  *    int df_timecol[]    - client controls which cols read as time
  50.  *
  51.  * functions 
  52.  *   int df_open(int max_using)
  53.  *      parses thru / index / using on command line
  54.  *      max_using is max no of 'using' columns allowed
  55.  *      returns number of 'using' cols specified, or -1 on error (?)
  56.  *
  57.  *   int df_readline(double vector[], int max)
  58.  *      reads a line, does all the 'index' and 'using' manipulation
  59.  *      deposits values into vector[]
  60.  *      returns
  61.  *          number of columns parsed  [0=not blank line, but no valid data],
  62.  *          DF_EOF for EOF
  63.  *          DF_UNDEFINED - undefined result during eval of extended using spec
  64.  *          DF_FIRST_BLANK for first consecutive blank line
  65.  *          DF_SECOND_BLANK for second consecutive blank line
  66.  *            will return FIRST before SECOND
  67.  *
  68.  * if a using spec was given, lines not fulfilling spec are ignored.
  69.  * we will always return exactly the number of items specified
  70.  *
  71.  * if no spec given, we return number of consecutive columns we parsed.
  72.  * 
  73.  * if we are processing indexes, seperated by 'n' blank lines,
  74.  * we will return n-1 blank lines before noticing the index change
  75.  *
  76.  *   void df_close()
  77.  *     closes a currently open file.
  78.  *
  79.  *    void f_dollars(x)
  80.  *    void f_column()    actions for expressions using $i, column(j), etc
  81.  *    void f_valid()     
  82.  * 
  83.  *
  84.  * line parsing slightly differently from previous versions of gnuplot...
  85.  * given a line containing fewer columns than asked for, gnuplot used to make
  86.  * up values... I say that if I have explicitly said 'using 1:2:3', then if
  87.  * column 3 doesn't exist, I dont want this point...
  88.  * a column number of 0 means generate a value... as before, this value
  89.  * is useful in 2d, but probably meaningless in 3d ???
  90.  *
  91.  * 20/5/95 : accept 1.23d4 in place of e (but not in scanf string)
  92.  *         : autoextend data line buffer and MAX_COLS
  93.  *
  94.  */
  95. /*}}}*/
  96.  
  97. #include <stdio.h>
  98. #include <stdlib.h>
  99. #include <math.h>
  100. #include <ctype.h>
  101. #include <time.h>
  102. #include <assert.h>
  103.  
  104. #include "plot.h"
  105. #include "fnproto.h"  /* check prototypes against our defns */
  106. #include "binary.h"
  107. #include "setshow.h"
  108.  
  109. /* if you change this, change the scanf in readline */
  110. #define NCOL   7            /* max using specs     */
  111.  
  112. /*{{{  static fns*/
  113. static int get_time_cols __P((char *fmt));
  114. static void mod_def_usespec __P((int specno, int jump));
  115. static int check_missing __P((char *s));
  116. /*}}}*/
  117.  
  118. /*{{{  variables*/
  119. struct use_spec_s { int column; struct at_type *at; };
  120.  
  121. /* public variables client might access */
  122.  
  123. int df_no_use_specs;  /* how many using columns were specified */
  124. int df_line_number;
  125. int df_datum;  /* suggested x value if none given */
  126. TBOOLEAN df_binary = FALSE; /* this is a binary file */
  127. int df_eof=0;
  128. int df_timecol[NCOL];
  129.  
  130. /* private variables */
  131.  
  132. /* in order to allow arbitrary data line length, we need to use the heap
  133.  * might consider free-ing it in df_close, especially for small systems
  134.  */
  135. static char *line=NULL;
  136. static int max_line_len=0;
  137.  
  138. static FILE *data_fp=NULL;
  139. static TBOOLEAN pipe_open = FALSE;
  140. static TBOOLEAN mixed_data_fp = FALSE;
  141.  
  142. #ifndef MAXINT  /* should there be one already defined ? */
  143. #ifdef INT_MAX  /* in limits.h ? */
  144. #define MAXINT INT_MAX
  145. #else
  146. #define MAXINT ((~0)>>1)
  147. #endif
  148. #endif
  149.  
  150. /* stuff for implementing index */
  151. static int blank_count=0;      /* how many blank lines recently */
  152. static int df_lower_index=0;  /* first mesh required */
  153. static int df_upper_index=MAXINT;
  154. static int df_index_step=1;  /* 'every' for indices */
  155. static int df_current_index;   /* current mesh */
  156.  
  157. /* stuff for every point:line */
  158. static int everypoint=1;
  159. static int firstpoint=0;
  160. static int lastpoint=MAXINT;
  161. static int everyline=1;
  162. static int firstline=0;
  163. static int lastline=MAXINT;
  164. static int point_count=-1;  /* point counter - preincrement and test 0 */
  165. static int line_count=0;  /* line counter */
  166.  
  167. /* parsing stuff */
  168. static struct use_spec_s use_spec[NCOL];
  169. static char df_format[MAX_LINE_LEN+1];
  170.  
  171. /* rather than three arrays which all grow dynamically, make one
  172.  * dynamic array of this structure
  173.  */
  174.  
  175. typedef struct df_column_struct {
  176.     double datum;
  177.     int good; /* 0=bad number (might still be a time), 1=good, -1=missing */
  178.     char *position;
  179. } df_column_struct;
  180.  
  181. static df_column_struct *df_column=NULL; /* we'll allocate space as needed */
  182. static int df_max_cols=0; /* space allocated */
  183. static int df_no_cols;    /* cols read */
  184.  
  185. /* external variables we need */
  186.  
  187. extern int c_token, num_tokens;
  188. extern char timefmt[]; /* I would rather not need this, but ... */
  189. /* columns needing timefmt are passed in df_timecol[] after df_open */
  190.  
  191. /* jev -- for passing data thru user-defined function */
  192. extern struct udft_entry ydata_func;
  193. extern struct udft_entry *dummy_func;
  194. extern char dummy_var[MAX_NUM_VAR][MAX_ID_LEN+1];
  195. extern char c_dummy_var[MAX_NUM_VAR][MAX_ID_LEN+1];
  196.  
  197. extern double min_array[], max_array[];
  198. /*}}}*/
  199.  
  200. /*{{{  replacement sscanf for purec*/
  201. #ifdef __PUREC__
  202. /*
  203.  * a substitute for PureC's buggy sscanf.
  204.  * this uses the normal sscanf and fixes the following bugs:
  205.  * - whitespace in format matches whitespace in string, but doesn't
  206.  *   require any. ( "%f , %f" scans "1,2" correctly )
  207.  * - the ignore value feature works (*). this created an address error
  208.  *   in PureC.
  209.  */
  210.  
  211. #include <stdarg.h>
  212. #include <string.h>
  213.  
  214. int purec_sscanf( const char *string, const char *format, ... )
  215. {
  216.   va_list args;
  217.   int cnt=0;
  218.   char onefmt[256];
  219.   char buffer[256];
  220.   const char *f=format;
  221.   const char *s=string;
  222.   char *f2;
  223.   char ch;
  224.   int ignore;
  225.   void *p;
  226.   int *ip;
  227.   int pos;
  228.  
  229.   va_start(args,format);
  230.   while( *f && *s ) {
  231.     ch=*f++;
  232.     if( ch!='%' ) {
  233.       if(isspace(ch)) {
  234.         /* match any number of whitespace */
  235.         while(isspace(*s)) s++;
  236.       } else {
  237.         /* match exactly the character ch */
  238.         if( *s!=ch ) goto finish;
  239.         s++;
  240.       }
  241.     } else {
  242.       /* we have got a '%' */
  243.       ch=*f++;
  244.       if( ch=='%' ) {
  245.         /* match exactly % */
  246.         if( *s!=ch ) goto finish;
  247.         s++;
  248.       } else {
  249.         f2=onefmt;
  250.         *f2++='%';
  251.         *f2++=ch;
  252.         ignore=0;
  253.         if( ch=='*' ) {
  254.           ignore=1;
  255.           ch=f2[-1]=*f++;
  256.         }
  257.         while( isdigit(ch) ) {
  258.           ch=*f2++=*f++;
  259.         }
  260.         if( ch=='l' || ch=='L' || ch=='h' ) {
  261.           ch=*f2++=*f++;
  262.         }
  263.         switch(ch) {
  264.           case '[':
  265.             while( ch && ch!=']' ) {
  266.               ch=*f2++=*f++;
  267.             }
  268.             if( !ch ) goto error;
  269.             break;
  270.           case 'e':
  271.           case 'f':
  272.           case 'g':
  273.           case 'd':
  274.           case 'o':
  275.           case 'i':
  276.           case 'u':
  277.           case 'x':
  278.           case 'c':
  279.           case 's':
  280.           case 'p':
  281.           case 'n': /* special case handled below */
  282.             break;
  283.           default:
  284.             goto error;
  285.         }
  286.         if( ch!='n' ) {
  287.           strcpy(f2,"%n");
  288.           if( ignore ) {
  289.             p=buffer;
  290.           } else {
  291.             p=va_arg(args,void *);
  292.           }
  293.           switch( sscanf( s, onefmt, p, &pos ) ) {
  294.             case EOF: goto error;
  295.             case  0 : goto finish;
  296.           }
  297.           if( !ignore ) cnt++;
  298.           s+=pos;
  299.         } else {
  300.           if( !ignore ) {
  301.             ip=va_arg(args,int *);
  302.             *ip=(int)(s-string);
  303.           }
  304.         }
  305.       }
  306.     }
  307.   }
  308.  
  309.   if( !*f ) goto finish;
  310.  
  311. error:
  312.   cnt=EOF;
  313. finish:
  314.   va_end(args);
  315.   return cnt;
  316. }
  317.  
  318. /* use the substitute now. I know this is dirty trick, but it works. */
  319. #define sscanf purec_sscanf
  320.  
  321. #endif /* __PUREC__ */
  322. /*}}}*/
  323.  
  324. /*{{{  int df_open(max_using)*/
  325. int df_open(max_using)
  326. int max_using;
  327.  
  328. /* open file, parsing using/thru/index stuff
  329.  * return number of using specs  [well, we have to return something !]
  330.  */
  331.  
  332. {
  333.     static char filename[MAX_LINE_LEN+1]="";
  334.     int i;
  335.     int name_token;
  336.     
  337.     /*{{{  close file if necessary*/
  338.     if (data_fp)
  339.         df_close();
  340.     /*}}}*/
  341.     
  342.     /*{{{  initialise static variables*/
  343.     df_format[0] = '\0';  /* no format string */
  344.     
  345.     df_no_use_specs = 0;
  346.     
  347.     for (i=0; i<NCOL; ++i)
  348.     {    use_spec[i].column=i+1; /* default column */
  349.         use_spec[i].at = NULL;  /* no expression */
  350.     }
  351.     
  352.     if (max_using > NCOL)
  353.         max_using = NCOL;
  354.     
  355.     df_datum = 0;
  356.     df_line_number=0;
  357.     
  358.     df_lower_index = 0;
  359.     df_index_step = 1;
  360.     df_upper_index = MAXINT;
  361.     
  362.     df_current_index=0;
  363.     blank_count = 2;
  364.     /* by initialising blank_count, leading blanks will be ignored */
  365.     
  366.     everypoint = everyline=1;  /* unless there is an every spec */
  367.     firstpoint=firstline=0;
  368.     lastpoint=lastline=MAXINT;
  369.     
  370.     df_eof=0;
  371.     
  372.     memset(df_timecol, 0, sizeof(df_timecol));
  373.     
  374.     df_binary=1;
  375.     /*}}}*/
  376.  
  377.     assert(max_using <= NCOL);
  378.  
  379.     /* empty name means re-use last one */
  380.  
  381.     {    char name[MAX_LINE_LEN+1];
  382.         quote_str(name, c_token, MAX_LINE_LEN);
  383.         if (name[0])
  384.             strcpy(filename, name);
  385.         else if (!filename[0])
  386.             int_error("No previous filename", c_token);
  387.     }
  388.     name_token = c_token++;
  389.  
  390.     /* defer opening until we have parsed the modifiers... */
  391.  
  392.     /*{{{  look for binary*/
  393.     if (almost_equals(c_token, "bin$ary"))
  394.     {
  395.         ++c_token;
  396.         df_binary=TRUE;
  397.     }
  398.     else
  399.         df_binary=FALSE;
  400.     /*}}}*/
  401.  
  402.     /*{{{  deal with index*/
  403.     if (almost_equals(c_token, "i$ndex")) {
  404.         struct value a;
  405.     
  406.         if (df_binary)
  407.             int_error("Binary file format does not allow more than one surface per file",c_token);
  408.             
  409.         ++c_token;
  410.         df_lower_index = (int)real(const_express(&a));
  411.         if (equals(c_token, ":")) {
  412.             ++c_token;
  413.             df_upper_index = (int)magnitude(const_express(&a));
  414.             if (df_upper_index < df_lower_index)
  415.                 int_error("Upper index should be bigger than lower index", c_token);
  416.     
  417.             if (equals(c_token, ":")) {
  418.                 ++c_token;
  419.                 df_index_step = (int)magnitude(const_express(&a));
  420.                 if (df_index_step < 1)
  421.                     int_error("Index step must be positive", c_token);
  422.             }
  423.         }
  424.         else
  425.             df_upper_index = df_lower_index;
  426.     }
  427.     /*}}}*/
  428.  
  429.     /*{{{  deal with every*/
  430.     if (almost_equals(c_token, "ev$ery")) {
  431.         struct value a;
  432.     
  433.         /* allow empty fields - every a:b:c::e
  434.          * we have already established the defaults
  435.          */
  436.     
  437.         if (!equals(++c_token, ":")) {
  438.             everypoint = (int)real(const_express(&a));
  439.             if (everypoint<1)
  440.                 int_error("Expected positive integer", c_token);
  441.         }
  442.     
  443.         /* if it fails on first test, no more tests will succeed. If it
  444.          * fails on second test, next test will succeed with correct c_token
  445.          */
  446.         if (equals(c_token, ":") && !equals(++c_token, ":")) {
  447.             everyline = (int)real(const_express(&a));
  448.             if (everyline<1)
  449.                 int_error("Expected positive integer", c_token);
  450.         }
  451.     
  452.         if (equals(c_token, ":") && !equals(++c_token, ":")) {
  453.             firstpoint = (int)real(const_express(&a));
  454.             if (firstpoint<0)
  455.                 int_error("Expected non-negative integer", c_token);
  456.         }
  457.     
  458.         if (equals(c_token, ":") && !equals(++c_token, ":")) {
  459.             firstline = (int)real(const_express(&a));
  460.             if (firstline<0)
  461.                 int_error("Expected non-negative integer", c_token);
  462.         }
  463.     
  464.         if (equals(c_token, ":") && !equals(++c_token, ":")) {
  465.             lastpoint = (int)real(const_express(&a));
  466.             if (lastpoint<firstpoint)
  467.                 int_error("Last point must not be before first point", c_token);
  468.         }
  469.     
  470.         if (equals(c_token, ":")) {
  471.             ++c_token;
  472.             lastline = (int)real(const_express(&a));
  473.             if (lastline<firstline)
  474.                 int_error("Last line must not be before first line", c_token);
  475.         }
  476.     }
  477.     /*}}}*/
  478.     
  479.     /*{{{  deal with thru*/
  480.     /* jev -- support for passing data from file thru user function */
  481.     
  482.     if (almost_equals(c_token, "thru$")) {
  483.         c_token++;
  484.         if (ydata_func.at)
  485.             free(ydata_func.at);
  486.         strcpy(c_dummy_var[0], dummy_var[0]);
  487.         /* allow y also as a dummy variable.
  488.          * during plot, c_dummy_var[0] and [1] are 'sacred'
  489.          * ie may be set by  splot [u=1:2] [v=1:2], and these
  490.          * names are stored only in c_dummy_var[]
  491.          * so choose dummy var 2 - can anything vital be here ?
  492.          */
  493.         dummy_func = &ydata_func;
  494.         strcpy(c_dummy_var[2], "y");
  495.         ydata_func.at = perm_at();
  496.         dummy_func = NULL;
  497.     } else {
  498.         if (ydata_func.at)
  499.             free(ydata_func.at);
  500.         ydata_func.at = NULL;
  501.     }
  502.     /*}}}*/
  503.  
  504.     /*{{{  deal with using*/
  505.     if (almost_equals(c_token,"u$sing"))
  506.     {
  507.         if (!END_OF_COMMAND && !isstring(++c_token))
  508.         {
  509.             struct value a;
  510.     
  511.             do  /* must be at least one */
  512.             {
  513.                 if (df_no_use_specs >= max_using)
  514.                     int_error("Too many columns in using specification", c_token);
  515.                     
  516.                 if (equals(c_token, "("))
  517.                 {
  518.                     dummy_func=NULL;  /* no dummy variables active */
  519.                     use_spec[df_no_use_specs++].at = perm_at();  /* it will match ()'s */
  520.                 }
  521.                 else
  522.                     use_spec[df_no_use_specs++].column = 
  523.     (int)magnitude(const_express(&a));
  524.             } while (equals(c_token,":") && ++c_token);
  525.         }
  526.     
  527.         if (!END_OF_COMMAND && isstring(c_token)) {
  528.             if (df_binary)
  529.                 int_error("Format string meaningless with binary data",NO_CARET);
  530.                 
  531.             quote_str(df_format, c_token, MAX_LINE_LEN);
  532.             if (!valid_format( df_format))
  533.                 int_error( "Please use a double conversion %lf", c_token);
  534.                                       
  535.             c_token++;    /* skip format */
  536.         }
  537.     }
  538.     /*}}}*/
  539.  
  540.     /*{{{  more variable inits*/
  541.     point_count = -1;  /* we preincrement */
  542.     line_count = 0;
  543.     
  544.     /* here so it's not done for every line in df_readline */
  545.     if (max_line_len < 160)
  546.         line = (char *)alloc(max_line_len=160, "datafile line buffer");
  547.     
  548.     
  549.     /*}}}*/
  550.  
  551.  
  552. /*{{{  open file*/
  553. #if defined(unix) || defined(PIPES)
  554.     if (*filename == '<') {
  555.         if ((data_fp = popen(filename + 1, "r")) == (FILE *) NULL)
  556.             os_error("cannot create pipe for data", name_token);
  557.         else
  558.             pipe_open = TRUE;
  559.     } else
  560. #endif /* unix || PIPES */
  561.     if (*filename == '-'){
  562.         data_fp=lf_top();
  563.         if(!data_fp) data_fp=stdin;
  564.         mixed_data_fp=TRUE; /* don't close command file */
  565.     } else
  566.         if ((data_fp = fopen(filename, "r")) == (FILE *) NULL)
  567.             os_error("can't open data file", name_token);
  568. /*}}}*/
  569.  
  570.     return df_no_use_specs;
  571. }
  572. /*}}}*/
  573.  
  574. /*{{{  void df_close()*/
  575. void df_close()
  576. {
  577.     int i;
  578.  
  579.     df_no_cols = 0;  /* paranoid - mark $n and column(n) as invalid */
  580.  
  581.     if (!data_fp)
  582.         return;
  583.  
  584.     if (ydata_func.at) {
  585.         free(ydata_func.at);
  586.         ydata_func.at = NULL;
  587.     }
  588.     
  589.     /*{{{  free any use expression storage*/
  590.     for (i=0; i<df_no_use_specs; ++i)
  591.         if (use_spec[i].at)
  592.         {
  593.             free(use_spec[i].at);
  594.             use_spec[i].at = NULL;
  595.         }
  596.     /*}}}*/
  597.  
  598.     if(!mixed_data_fp) {
  599. #if defined(unix) || defined(PIPES)
  600.         if (pipe_open) {
  601.                         (void) pclose(data_fp);
  602.                                     pipe_open = FALSE;
  603.         } else
  604. #endif /* unix || PIPES */
  605.         (void) fclose(data_fp);
  606.     }
  607.         mixed_data_fp=FALSE;
  608.             data_fp=NULL;
  609. }    
  610. /*}}}*/
  611.  
  612. /*{{{  int df_readline(v, max)*/
  613. /* do the hard work... read lines from file,
  614.  * - use blanks to get index number
  615.  * - ignore lines outside range of indices required
  616.  * - fill v[] based on using spec if given
  617.  */
  618.  
  619. int df_readline(v, max)
  620. double v[];
  621. int max;
  622. {
  623.     assert(data_fp != NULL);
  624.     assert(!df_binary);
  625.     assert(max <= NCOL);
  626.     assert(max_line_len); /* alloc-ed in df_open() */
  627.  
  628.     /* catch attempt to read past EOF on mixed-input */
  629.     if (df_eof)
  630.         return DF_EOF;
  631.         
  632.     while (fgets(line, max_line_len-1, data_fp) != (char *) NULL)
  633.         /*{{{  process line*/
  634.         {
  635.             char *s;
  636.             int line_okay = 1;
  637.             int output=0;  /* how many numbers written to v[] */
  638.         
  639.             /*{{{  if line was longer than our buffer, realloc and read some more*/
  640.             {
  641.                 int len=strlen(line);
  642.                 while (line[len-1] != '\n') {
  643.                     /* buffer we provided may not be full - dont grab extra
  644.                      * memory un-necessarily. This may trap a problem with last
  645.                      * line in file not being properly terminated - each time
  646.                      * through a replot loop, it was doubling buffer size
  647.                      */
  648.                     if ( (max_line_len-len) < 32)
  649.                         line = ralloc(line, max_line_len*=2, "datafile line buffer");
  650.             
  651.                     if (!fgets(line+len-1, max_line_len - len, data_fp))
  652.                         break; /* unexpected end of file, but we have something to do */
  653.             
  654.                     /* get length of just the new bit, rather than whole lot */
  655.                     len += strlen(line+len);
  656.                 }
  657.             }
  658.             /*}}}*/
  659.             
  660.             s=line;
  661.             ++df_line_number;
  662.             ++df_datum;
  663.             df_no_cols = 0;
  664.             
  665.             /*{{{  check for blank lines, and reject by index/every*/
  666.             /*{{{  skip leading spaces*/
  667.             while (isspace(*s))
  668.                 ++s;  /* will skip the \n too, to point at \0  */
  669.             /*}}}*/
  670.                 
  671.             /*{{{  skip comments*/
  672.             if (is_comment(*s))
  673.                    continue;        /* ignore comments */
  674.             /*}}}*/
  675.             
  676.             /*{{{  check EOF on mixed data*/
  677.             if (mixed_data_fp && is_EOF(*s))
  678.             {
  679.                 df_eof=1;  /* trap attempts to read past EOF */
  680.                 return DF_EOF;
  681.             }
  682.             /*}}}*/
  683.             
  684.             if (*s==0)
  685.                 /*{{{  its a blank line - update counters and continue or return*/
  686.                 {
  687.                     /* argh - this is complicated !  we need to
  688.                      *   ignore it if we haven't reached first index
  689.                      *   report EOF if passed last index
  690.                      *   report blank line unless we've already done 2 blank lines
  691.                      *
  692.                      * - I have probably missed some obvious way of doing all this,
  693.                      * but its getting late
  694.                      */
  695.                 
  696.                     point_count=-1;  /* restart counter within line */
  697.                 
  698.                     if (++blank_count==1) {
  699.                         /* first blank line */
  700.                         ++line_count;
  701.                     }
  702.                     
  703.                     if (blank_count == 2)
  704.                     {    /* just reached end of a group/surface */
  705.                         ++df_current_index;
  706.                         line_count = 0;
  707.                         df_datum = 0;
  708.                         /* ignore line if current_index has just become
  709.                          * first required one - client doesn't want this
  710.                          * blank line. While we're here, check for <=
  711.                          * - we need to do it outside this conditional, but
  712.                          * probably no extra cost at assembler level
  713.                          */
  714.                         if (df_current_index <= df_lower_index)
  715.                             continue;  /* dont tell client */
  716.                 
  717.                         /* df_upper_index is MAXINT-1 if we are not doing index */
  718.                         if (df_current_index > df_upper_index)
  719.                         {
  720.                             /* oops - need to gobble rest of input if mixed */
  721.                             if (mixed_data_fp)
  722.                                 continue;
  723.                             else
  724.                             {
  725.                                 df_eof=1;
  726.                                 return DF_EOF; /* no point continuing */
  727.                             }
  728.                         }
  729.                     }
  730.                 
  731.                     /* dont tell client if we haven't reached first index */
  732.                     if (df_current_index < df_lower_index)
  733.                         continue;
  734.                 
  735.                     /* ignore blank lines after blank_index */
  736.                     if (blank_count > 2)
  737.                         continue;
  738.                 
  739.                     return DF_FIRST_BLANK - (blank_count-1);
  740.                 }
  741.                 /*}}}*/
  742.             
  743.             /* get here => was not blank */
  744.                 
  745.             blank_count = 0;
  746.             
  747.             /*{{{  ignore points outside range of index*/
  748.             /* we try to return end-of-file as soon as we pass upper index,
  749.              * but for mixed input stream, we must skip garbage
  750.              */
  751.              
  752.             if (df_current_index < df_lower_index ||
  753.                 df_current_index > df_upper_index ||
  754.                  ((df_current_index - df_lower_index)%df_index_step) != 0)
  755.                 continue;
  756.             /*}}}*/
  757.             
  758.             /*{{{  reject points by every*/
  759.             /* accept only lines with (line_count%everyline)==0 */
  760.             
  761.             if (line_count<firstline || line_count > lastline ||
  762.                 (line_count-firstline)%everyline != 0
  763.                )
  764.                 continue;
  765.             
  766.             /* update point_count. ignore point if point_count%everypoint != 0 */
  767.             
  768.             if (++point_count < firstpoint || point_count > lastpoint ||
  769.                 (point_count-firstpoint)%everypoint != 0
  770.                )
  771.                 continue;
  772.             /*}}}*/
  773.             /*}}}*/
  774.             
  775.             if (*df_format)
  776.                 /*{{{  do a sscanf*/
  777.                 {
  778.                     int i;
  779.                 
  780.                     assert(NCOL==7);
  781.                     
  782.                     /* check we have room for at least 7 columns */
  783.                     if (df_max_cols < 7)
  784.                         df_column = (df_column_struct *)ralloc(df_column, (df_max_cols=7)*sizeof(df_column_struct), "datafile columns");
  785.                 
  786.                     df_no_cols = sscanf(line, df_format,
  787.                        &df_column[0].datum,
  788.                        &df_column[1].datum,
  789.                        &df_column[2].datum,
  790.                        &df_column[3].datum,
  791.                        &df_column[4].datum,
  792.                        &df_column[5].datum,
  793.                        &df_column[6].datum);
  794.                 
  795.                     if (df_no_cols == EOF)
  796.                     {
  797.                         df_eof=1;
  798.                         return DF_EOF;  /* tell client */
  799.                     }
  800.                     for (i=0; i < df_no_cols; ++i ) /* may be zero */
  801.                     {    df_column[i].good=1;
  802.                         df_column[i].position=NULL;  /* cant get a time */
  803.                     }
  804.                 }
  805.                 /*}}}*/
  806.             else
  807.                 /*{{{  read the data column by column*/
  808.                 {
  809.                     /* implement our own sscanf that skips lines with invalid
  810.                      * data if a using statement was given
  811.                      * convert the array to its constituents
  812.                      */
  813.                 
  814.                     df_no_cols = 0;
  815.                     
  816.                     while (*s)
  817.                     {
  818.                         int used;
  819.                 
  820.                         /* check store - double max cols or add 20, whichever is greater */
  821.                         if (df_max_cols <= df_no_cols)
  822.                             df_column=(df_column_struct *)ralloc(df_column, (df_max_cols += (df_max_cols < 20 ? 20 : df_max_cols))*sizeof(df_column_struct), "datafile column");
  823.                 
  824.                         /* have always skipped spaces at this point */
  825.                         df_column[df_no_cols].position = s;
  826.                 
  827.                         if (check_missing(s))
  828.                             df_column[df_no_cols].good = -1;
  829.                         else {
  830.                             /* cannot trust strtod - eg strtod("-",&p) */
  831.                             df_column[df_no_cols].good = sscanf(s, "%lf%n", &df_column[df_no_cols].datum, &used);
  832.                 
  833.                             /* it might be a fortran double or quad precision. 'used'
  834.                              * is only safe if good is 1
  835.                              */
  836.                              
  837.                             if (df_column[df_no_cols].good &&
  838.                                 (s[used]=='d' || s[used]=='D' || s[used]=='q' || s[used]=='Q')
  839.                                ) {
  840.                                /* might be fortran double */
  841.                                 s[used]='e';
  842.                                 /* and try again */
  843.                                 df_column[df_no_cols].good = sscanf(s, "%lf", &df_column[df_no_cols].datum);
  844.                             }
  845.                         }
  846.                 
  847.                         ++df_no_cols;
  848.                         /*{{{  skip chars to end of column*/
  849.                         while ((!isspace(*s)) && (*s != '\0'))
  850.                             ++s;
  851.                         /*}}}*/
  852.                         /*{{{  skip spaces to start of next column*/
  853.                         while (isspace(*s))
  854.                             ++s;
  855.                         /*}}}*/
  856.                     }
  857.                 }
  858.                 /*}}}*/
  859.         
  860.             /*{{{  copy column[] to v[] via use[]*/
  861.             {
  862.                 int limit=(df_no_use_specs ? df_no_use_specs : NCOL);
  863.                 if (limit>max)
  864.                     limit=max;
  865.                 
  866.                 for (output=0; output<limit; ++output)
  867.                 {
  868.                     /* if there was no using spec, column is output+1 and at=NULL */
  869.                     int column=use_spec[output].column;
  870.             
  871.                     if (use_spec[output].at)
  872.                     {    struct  value a;
  873.                         /* no dummy values to set up prior to... */
  874.                         evaluate_at(use_spec[output].at, &a);
  875.                         if (undefined)
  876.                             return DF_UNDEFINED;  /* store undefined point in plot */
  877.                             
  878.                         v[output]=real(&a);
  879.                     }
  880.                     else if (df_timecol[output])
  881.                     {    struct tm tm;
  882.                         if (column >= df_no_cols ||
  883.                             df_column[column-1].good == -1 /* missing */ ||
  884.                             !df_column[column-1].position ||
  885.                             !gstrptime(df_column[column-1].position,timefmt,&tm)
  886.                            )
  887.                         {
  888.                             /* line bad only if user explicitly asked for this column */
  889.                             if (df_no_use_specs)
  890.                                 line_okay=0;
  891.             
  892.                             /* return or ignore line depending on line_okay */
  893.                             break;
  894.                         }
  895.                         v[output] = (double) gtimegm(&tm);
  896.                     }
  897.                     else if (column)
  898.                     {
  899.                         v[output] = df_column[column-1].datum;
  900.                         if ( (column > df_no_cols) || df_column[column-1].good!=1)
  901.                         {
  902.                             /* line bad only if user explicitly asked for this column */
  903.                             if (df_no_use_specs)
  904.                                 line_okay=0;
  905.                             break;  /* return or ignore depending on line_okay */ 
  906.                         }
  907.                     }
  908.                     else
  909.                         v[output] = df_datum;    /* using 0 */
  910.                 }
  911.             }
  912.             /*}}}*/
  913.         
  914.             if (!line_okay)
  915.                 continue;
  916.         
  917.             /* output == df_no_use_specs if using was specified
  918.              * - actually, smaller of df_no_use_specs and max
  919.              */
  920.             assert (df_no_use_specs==0 || output==df_no_use_specs || output==max);
  921.             
  922.             return output;
  923.         
  924.         }
  925.         /*}}}*/
  926.  
  927.     /* get here => fgets failed */
  928.  
  929.     df_no_cols = 0;  /* no longer needed - mark column(x) as invalid */
  930.     df_eof=1;
  931.     return DF_EOF;
  932. }
  933. /*}}}*/
  934.  
  935. /*{{{  int df_2dbinary(this_plot)*/
  936. int df_2dbinary(this_plot)
  937. struct curve_points *this_plot;
  938. {
  939.     int_error("Binary file format for 2d data not yet defined", NO_CARET);
  940.     return 0;  /* keep compiler happy */
  941. }
  942. /*}}}*/
  943.  
  944. /*{{{  int df_3dbinary(this_plot, ret_this_iso)*/
  945. /*
  946.  * formerly in gnubin.c
  947.  *
  948.  * modified by div for 3.6
  949.  *   obey the 'every' field from df_open
  950.  *   outrange points are marked as such, not omitted
  951.  *   obey using - treat x as column 1, y as col 2 and z as col 3
  952.  *   ( ie $1 gets x, $2 gets y, $3 gets z)
  953.  *
  954.  *  we are less optimal for case of log plot and no using spec,
  955.  * (call log too often) but that is price for flexibility
  956.  * I suspect it didn't do autoscaling of x and y for log scale
  957.  * properly ?
  958.  *
  959.  * Trouble figuring out file format ! Is it
  960.  
  961.  width  x1  x2  x3  x4  x5 ...
  962.    y1   z11 z12 z13 z14 z15 ...
  963.    y2   x21 z22 z23 .....
  964.    .    .
  965.    .        .
  966.    .             .
  967.  
  968.  * with perhaps x and y swapped...
  969.  *
  970.  * - presumably rows continue to end of file, hence no indexing...
  971.  *
  972.  * Last update: 3/3/92 for Gnuplot 3.24.
  973.  * Created from code for written by RKC for gnuplot 2.0b.
  974.  *
  975.  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
  976.  * Added user-specified bases for log scaling.
  977.  *
  978.  * Copyright (c) 1991,1992 Robert K. Cunningham, MIT Lincoln Laboratory
  979.  *
  980.  */
  981.  
  982. /*
  983.   Here we keep putting new plots onto the end of the linked list
  984.  
  985.   We assume the data's x,y values have x1<x2, x2<x3... and 
  986.                                        y1<y2, y2<y3... .
  987.   Actually, I think the assumption is less stron than that--it looks like
  988.   the direction just has to be the same.
  989.   This routine expects the following to be properly initialized:
  990.       is_log_x, is_log_y, and is_log_z 
  991.       base_log_x, base_log_y, and base_log_z 
  992.       log_base_log_x, log_base_log_y, and log_base_log_z 
  993.       xmin,ymin, and zmin
  994.       xmax,ymax, and zmax
  995.       autoscale_lx, autoscale_ly, and autoscale_lz
  996.  
  997.       does the autoscaling into the array versions (min_array[], max_array[])
  998. */
  999.  
  1000. int
  1001.   df_3dbinary(this_plot)
  1002. struct surface_points *this_plot;
  1003. {
  1004.     float GPFAR * GPFAR *matrix, GPFAR *rt, GPFAR *ct;
  1005.     int nr,nc;
  1006.     int width,height;
  1007.     int row,col;
  1008.     struct iso_curve *this_iso;
  1009.     double used[3]; /* output from using manip */
  1010.     struct coordinate *point;
  1011.     
  1012.     assert(df_binary);
  1013.     
  1014.     if (df_eof)
  1015.         return 0; /* hope caller understands this */
  1016.         
  1017.     if(!fread_matrix(data_fp,&matrix,&nr,&nc,&rt,&ct))
  1018.         int_error("Binary file read error: format unknown!",NO_CARET);
  1019.     
  1020.     if (nc==0 || nr==0)
  1021.         int_error("Read grid of zero height or zero width", NO_CARET);
  1022.     
  1023.     /* fread_matrix() drains the file */
  1024.     df_eof=1;
  1025.     
  1026.     this_plot->plot_type = DATA3D;
  1027.     this_plot->has_grid_topology = TRUE;
  1028.     
  1029.     if (df_no_use_specs != 0 && df_no_use_specs != 3)
  1030.             int_error("Current implementation requires full using spec",NO_CARET);
  1031.  
  1032.     if (df_max_cols < 3 &&
  1033.         !(df_column = (df_column_struct *)ralloc(df_column, (df_max_cols=3)*sizeof(df_column_struct), "datafile columns"))
  1034.        )
  1035.        int_error("Out of store in binary read", c_token);
  1036.  
  1037.     df_no_cols=3;
  1038.     df_column[0].good=df_column[1].good=df_column[2].good=1;
  1039.     
  1040.     assert(everyline > 0);
  1041.     assert(everypoint > 0);
  1042.     width=(nc-firstpoint+everypoint-1)/everypoint; /* ? ? ? ? ? */
  1043.     height=(nr-firstline+everyline-1)/everyline; /* ? ? ? ? ? */
  1044.     
  1045.     for(row=firstline; row < nr; row+=everyline){
  1046.         df_column[1].datum=rt[row];
  1047.  
  1048.         this_iso = iso_alloc(width);/*Allocate the correct number of entries*/
  1049.         point=this_iso->points;
  1050.  
  1051.         for(col = firstpoint; col< nc; col+=everypoint, ++point){/* Cycle through data */
  1052.             /*{{{  process one row*/
  1053.             int i;
  1054.             
  1055.             df_column[0].datum=ct[col];
  1056.             df_column[2].datum=matrix[row][col];
  1057.             
  1058.             /*{{{  pass through using spec*/
  1059.             for (i=0; i<3; ++i)
  1060.             {
  1061.                 int column=use_spec[i].column;
  1062.             
  1063.                 if (df_no_use_specs==0)
  1064.                     used[i]=df_column[i].datum;
  1065.                 else if (use_spec[i].at)
  1066.                 {
  1067.                     struct value a;
  1068.                     evaluate_at(use_spec[i].at, &a);
  1069.                     if (undefined)
  1070.                     {
  1071.                         point->type=UNDEFINED;
  1072.                         goto skip;  /* continue _outer_ loop */
  1073.                     }
  1074.                     used[i]=real(&a);
  1075.                 }
  1076.                 else if (column < 1 || column > df_no_cols)
  1077.                 {
  1078.                     point->type=UNDEFINED;
  1079.                     goto skip;
  1080.                 }
  1081.                 else
  1082.                     used[i]=df_column[column-1].datum;
  1083.             }
  1084.             /*}}}*/
  1085.             
  1086.             point->type=INRANGE; /* so far */
  1087.             
  1088.             /*{{{  autoscaling/clipping*/
  1089.             /*{{{  autoscale/range-check x*/
  1090.             if (used[0]>0 || !is_log_x)
  1091.             {
  1092.                 if (used[0] < min_array[FIRST_X_AXIS])
  1093.                 {    if (autoscale_lx & 1)
  1094.                         min_array[FIRST_X_AXIS] = used[0];
  1095.                     else
  1096.                         point->type=OUTRANGE;
  1097.                 }
  1098.             
  1099.                 if (used[0] > max_array[FIRST_X_AXIS])
  1100.                 {    if (autoscale_lx & 2)
  1101.                         max_array[FIRST_X_AXIS] = used[0];
  1102.                     else
  1103.                         point->type=OUTRANGE;
  1104.                 }
  1105.             }
  1106.             /*}}}*/
  1107.             
  1108.             /*{{{  autoscale/range-check y*/
  1109.             if (used[1]>0 || !is_log_y)
  1110.             {
  1111.                 if (used[0] < min_array[FIRST_Y_AXIS])
  1112.                 {    if (autoscale_ly & 1)
  1113.                         min_array[FIRST_Y_AXIS] = used[1];
  1114.                     else
  1115.                         point->type=OUTRANGE;
  1116.                 }
  1117.             
  1118.                 if (used[1] > max_array[FIRST_Y_AXIS])
  1119.                 {    if (autoscale_ly & 2)
  1120.                         max_array[FIRST_Y_AXIS] = used[0];
  1121.                     else
  1122.                         point->type=OUTRANGE;
  1123.                 }
  1124.             }
  1125.             /*}}}*/
  1126.             
  1127.             /*{{{  autoscale/range-check z*/
  1128.             if (used[2]>0 || !is_log_z)
  1129.             {
  1130.                 if (used[2] < min_array[FIRST_Z_AXIS])
  1131.                 {    if (autoscale_lz & 1)
  1132.                         min_array[FIRST_Z_AXIS] = used[2];
  1133.                     else
  1134.                         point->type=OUTRANGE;
  1135.                 }
  1136.             
  1137.                 if (used[2] > max_array[FIRST_Z_AXIS])
  1138.                 {    if (autoscale_lz & 2)
  1139.                         max_array[FIRST_Z_AXIS] = used[2];
  1140.                     else
  1141.                         point->type=OUTRANGE;
  1142.                 }
  1143.             }
  1144.             /*}}}*/
  1145.             /*}}}*/
  1146.             
  1147.             /*{{{  log x*/
  1148.             if (is_log_x)
  1149.             {
  1150.                 if (used[0] < 0.0)
  1151.                 {
  1152.                     point->type = UNDEFINED;
  1153.                     goto skip;
  1154.                 }
  1155.                 else if (used[0] == 0.0)
  1156.                 {
  1157.                     point->type = OUTRANGE;
  1158.                     used[0]=-VERYLARGE;
  1159.                 }
  1160.                 else
  1161.                     used[0] = log(used[0])/log_base_log_x;
  1162.             }
  1163.             /*}}}*/
  1164.             
  1165.             /*{{{  log y*/
  1166.             if (is_log_y)
  1167.             {
  1168.                 if (used[1] < 0.0)
  1169.                 {
  1170.                     point->type = UNDEFINED;
  1171.                     goto skip;
  1172.                 }
  1173.                 else if (used[1] == 0.0)
  1174.                 {
  1175.                     point->type=OUTRANGE;
  1176.                     used[1]=-VERYLARGE;
  1177.                 }
  1178.                 else
  1179.                     used[1] = log(used[1])/log_base_log_y;
  1180.             }
  1181.             /*}}}*/
  1182.             
  1183.             /*{{{  log z*/
  1184.             if (is_log_z)
  1185.             {
  1186.                 if (used[2] < 0.0)
  1187.                 {
  1188.                     point->type = UNDEFINED;
  1189.                     goto skip;
  1190.                 }
  1191.                 else if (used[2]==0.0)
  1192.                 {
  1193.                     point->type = OUTRANGE;
  1194.                     used[2]=-VERYLARGE;
  1195.                 }
  1196.                 else
  1197.                     used[2] = log(used[2])/log_base_log_z;
  1198.             }
  1199.             /*}}}*/
  1200.             
  1201.             point->x = used[0];
  1202.             point->y = used[1];
  1203.             point->z = used[2];
  1204.                     
  1205.                 
  1206.             /* some of you wont like this, but I say goto is for this */
  1207.             
  1208.             skip:
  1209.                 ; /* ansi requires this */
  1210.             /*}}}*/
  1211.         }
  1212.         this_iso->p_count = width;
  1213.         this_iso->next = this_plot->iso_crvs;
  1214.         this_plot->iso_crvs = this_iso;
  1215.         this_plot->num_iso_read++;
  1216.     }
  1217.     
  1218.     free_matrix(matrix,0,nr-1,0,nc-1);
  1219.     free_vector(rt,0,nr-1);
  1220.     free_vector(ct,0,nc-1);
  1221.     return(nc);
  1222. }
  1223. /*}}}*/
  1224.  
  1225. /* stuff for implementing the call-backs for picking up data values
  1226.  * do it here so we can make the variables private to this file
  1227.  */
  1228.  
  1229. /*{{{  void f_dollars(x)*/
  1230. void f_dollars(x)
  1231. union argument *x;
  1232. {
  1233.     int column = x->v_arg.v.int_val - 1;
  1234.         /* we checked it was an integer >= 0 at compile time */
  1235.     struct value a;
  1236.  
  1237.     if (column==-1)
  1238.     {
  1239.         push ( Gcomplex(&a, (double)df_datum, 0.0));  /* $0 */
  1240.     }
  1241.     else if (column >= df_no_cols || !df_column[column].good)
  1242.     {    undefined = TRUE;
  1243.         push (&(x->v_arg));  /* this okay ? */
  1244.     }
  1245.     else
  1246.         push( Gcomplex(&a, df_column[column].datum, 0.0) );
  1247. }
  1248. /*}}}*/
  1249.  
  1250. /*{{{  void f_column()*/
  1251. void f_column()
  1252. {
  1253.     struct value a;
  1254.     int column;
  1255.     (void) pop(&a);
  1256.     column = (int) magnitude(&a) - 1;
  1257.     if (column < 0 || column >= df_no_cols || !df_column[column].good)
  1258.     {    undefined = TRUE;
  1259.         push (&a);  /* any objection to this ? */
  1260.     }
  1261.     else
  1262.         push( Gcomplex(&a, df_column[column].datum, 0.0) );
  1263. }
  1264. /*}}}*/
  1265.  
  1266. /*{{{  void f_valid()*/
  1267. void f_valid()
  1268. {
  1269.     struct value a;
  1270.     int column,good;
  1271.     (void) pop(&a);
  1272.     column = (int) magnitude(&a) - 1;
  1273.     good = column >= 0 && column < df_no_cols && df_column[column].good;
  1274.     push (Ginteger(&a, good));
  1275. }
  1276. /*}}}*/
  1277.  
  1278. /* count columns in timefmt */
  1279. /*{{{  static int get_time_cols(fmt)*/
  1280. static int get_time_cols(fmt)
  1281. char *fmt; /* format string */
  1282. {
  1283.     int cnt,i;
  1284.     char *p;
  1285.  
  1286.     p = fmt;
  1287.     cnt = 0;
  1288.     while ( isspace(*p) )
  1289.         p++;
  1290.     if ( ! strlen(p)) 
  1291.         int_error("Empty time-data format",NO_CARET);
  1292.     cnt ++;
  1293.     for(i=0;i<strlen(p)-1;i++) {
  1294.         if ( isspace(p[i]) && !isspace(p[i+1]) )
  1295.             cnt++;
  1296.     }
  1297.     return(cnt);
  1298. }
  1299. /*}}}*/
  1300.  
  1301. /* modify default use_spec, applies for no user spec and time datacolumns */
  1302. /*{{{  static void mod_def_usespec(specno,jump)*/
  1303. static void mod_def_usespec(specno,jump)
  1304. int specno; /* which spec in ?:?:? */
  1305. int jump; /* no of columns in timefmt (time data) */
  1306. {
  1307.     int i;
  1308.  
  1309.     for (i=specno+1; i<NCOL; ++i) 
  1310.         use_spec[i].column += jump; /* add no of columns in time to the rest */
  1311.     df_no_use_specs = 0;
  1312. }
  1313. /*}}}*/
  1314.  
  1315. /*{{{  static int check_missing(s)*/
  1316. static int check_missing(s)
  1317. char *s;
  1318. {
  1319.     if ( missing_val != NULL ) {
  1320.         if ( !strncmp(s,missing_val,strlen(missing_val)) && isspace(s[strlen(missing_val)])) { 
  1321.             return (1);;  /* store undefined point in plot */
  1322.         }
  1323.     }
  1324.     return(0);
  1325. }
  1326. /*}}}*/
  1327.